#pragma once
#include <coroutine>
#include <concepts>
#include <utility>
#include <list>

#include <sys/epoll.h>

#include "examiner_control.hpp"
#include "globle_variable.hpp"
#include "my_utility.hpp"
#include "database.hpp"
#include "protocol.hpp"
#include "socket.hpp"

namespace ns_interface
{
    // 网络请求处理结构体
    struct worker
    {
        // 协程结构体
        struct coroutine_info
        {
            // 协程完成度
            enum class status_info : unsigned int
            {
                FAILURE = 0,
                UNFINISH,
                SUCCESS,
                EXCEPTION
            };

            // 协程标识
            enum class func_info : unsigned int
            {
                TASK = 0,
                READ,
                WRITE,
                OPEN,
                CLOSE
            };

            // 协程状态
            struct status
            {
                status(status_info ret = status_info::SUCCESS, func_info which = func_info::TASK);

                // 完成度
                status_info _ret;
                // 标识
                func_info _which;
            };

            // 协程承诺体
            struct promise_type
            {
                promise_type();

                // 获取协程结构体
                coroutine_info get_return_object();

                // 抛出协程内异常
                void unhandled_exception();
                
                // 协程初始化是否挂起
                std::suspend_never initial_suspend();

                // 协程销毁是否挂起
                std::suspend_always final_suspend() noexcept;

                // 存储协程结束返回值
                void return_value(status ret_val);

                // 存储协程暂停返回值
                std::suspend_always yield_value(status ret_val);

                // 异常指针
                std::exception_ptr _e_ptr;
                // 协程状态
                status _status;
            };

            using cor_handle = std::coroutine_handle<promise_type>;

            coroutine_info(const cor_handle& h = nullptr);
            ~coroutine_info();
            coroutine_info(const coroutine_info& other) = delete;
            coroutine_info(coroutine_info&& other);
            coroutine_info& operator=(const coroutine_info& other) = delete;
            coroutine_info& operator=(coroutine_info&& other);

            // 在外部抛出协程内异常
            void rethrow();

            // 获取协程内异常字符串指针
            const char* error();

            // 协程句柄
            cor_handle _h;
            // 协程完成度字符串视图
            constexpr static std::array<std::string_view, 4> _status_to_string = { "failure", "unfinish", "success", "exception" };
            // 协程标识字符串视图
            constexpr static std::array<std::string_view, 5> _func_to_string = { "task", "read", "write", "open", "close" };
        };

        worker(int fd = -1);
        worker(const worker& other) = delete;
        worker& operator=(const worker& other) = delete;
        worker(worker&& other);
        worker& operator=(worker&& other);

        // 收发报文
        coroutine_info parse();

        // 处理网页请求
        coroutine_info bodyProcessing();

        // 拉取404html
        void notFound();

        // 拉取网页骨架资源
        void normalResourse(const std::filesystem::path& target, const std::string& extension);

        // 拉取题库资源
        void totalResourse();

        // 拉取具体题目资源
        void singleResourse(const std::string& name);

        // 重置
        void reset(int epoll_fd);

        // 接收网络请求
        template<class HTTP_TYPE>
        requires std::derived_from<HTTP_TYPE, http_base>
        coroutine_info recv(int fd, HTTP_TYPE& input);

        // 发送网络响应
        template<class HTTP_TYPE>
        requires std::derived_from<HTTP_TYPE, http_base>
        coroutine_info send(int fd, const HTTP_TYPE& output);

        // 客户端网络请求
        http_request _input;
        // 客户端网络响应
        http_response _output;
        // io类协程
        coroutine_info _io;
        // 报文处理协程
        coroutine_info _body;
        // 报文解析协程
        coroutine_info _self;
        // 代解析请求报文缓冲区
        std::string _buf;
        // tcp连接文件描述符
        int _fd;
        // 请求是否需要回复
        bool _feedback;
    };

    // 网络节点池
    class node_allocator
    {
    private:
        // 网络节点结构体
        class node
        {
        public:
            node();
            node(worker&& input);
            node(const node& other) = delete;
            node(node&& other);

            // 节点是否过期
            bool check();

            // 提取节点信息
            worker get();
        private:
            // 节点荷载
            worker _data;
            // 节点存储起始时间
            const std::chrono::steady_clock::time_point _start;
        };
    public:
        node_allocator();
        ~node_allocator();
        node_allocator(const node_allocator& other) = delete;
        node_allocator(node_allocator&& other);

        // 网络节点申请
        void allocate(std::list<worker>& input, int connection_fd);

        // 网络节点回收
        void recycle(std::list<worker>& output, std::list<worker>::iterator& it);

        // 垃圾回收器
        void GC(bool signal);
    private:
        // 可用节点队列
        std::list<node> _pool;
        // 回收器线程
        std::thread _th;
        // 回收器锁
        std::mutex _m;
        // 回收器条件变量
        std::condition_variable _cond;
        // 节点队列锁
        spin_lock _sp;
        // 回收器休眠起始时间点
        std::chrono::steady_clock::time_point _start;
    };

    // 网络协程调度器
    class scheduler
    {
    private:
        // 处理线程结构体
        struct thread_info
        {
            thread_info();
            ~thread_info();

            // 处理线程
            std::thread _th;
            // 处理线程休眠锁
            std::mutex _m;
            // 处理线程条件变量
            std::condition_variable _cond;
            // 处理线程锁
            spin_lock _sp;
            // 监听文件描述符
            int _epoll_fd;
        };
    public:
        scheduler();
        ~scheduler();
        scheduler(const scheduler& other) = delete;
        scheduler(scheduler&& other) = delete;
        const scheduler& operator=(const scheduler& other) = delete;
        const scheduler& operator=(scheduler&& other) = delete;

        // 网络请求分配函数
        void dispatch(int connection_fd);

        // 调度线程入口
        void thread_entry(size_t group);

        // 唤醒在epoll上阻塞的线程退出
        void setTrigger(int fd);
    private:
        // 处理线程队列
        std::vector<thread_info> _execute_stream_arr;
        // 每个线程正在处理的网络请求数量
        std::vector<std::list<worker>> _process_queue_arr;
        // 每个线程等待处理的网络请求数量
        std::vector<std::list<worker>> _waiting_queue_arr;
        // 每个线程正在处理的网络请求数量
        std::vector<std::atomic<size_t>> _total_node_arr;
        // 节点池
        node_allocator _node_pool;
        // 唤醒文件描述符
        int _trigger_fd;
    };
}